package com.xmall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xmall.define.base.ResultCode;
import com.xmall.define.constants.CommonConstants;
import com.xmall.define.dto.es.EsSkuDto;
import com.xmall.define.dto.product.SkuInfoDto;
import com.xmall.exception.XmallException;
import com.xmall.product.define.dict.UpStatusEnum;
import com.xmall.product.define.dto.group.GroupDto;
import com.xmall.product.define.dto.saleAttr.SpuSaleAttrDto;
import com.xmall.product.define.dto.spu.SpuBaseAttrDto;
import com.xmall.product.define.dto.spu.SpuInfoDto;
import com.xmall.product.define.dto.spu.SpuResponseDto;
import com.xmall.product.define.request.group.GroupQueryParams;
import com.xmall.product.define.request.spu.SkuQueryParams;
import com.xmall.product.define.request.spu.SpuListPageQueryRequest;
import com.xmall.product.define.request.spu.SpuUpdateRequest;
import com.xmall.product.entity.SkuInfo;
import com.xmall.product.entity.SpuInfo;
import com.xmall.product.mapper.SpuInfoMapper;
import com.xmall.product.service.*;
import com.xmall.product.service.other.IMsgService;
import com.xmall.product.utils.ConvertUtils;
import com.xmall.utils.XmallUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

/**
 * 商品spu信息 服务实现类
 */
@Service
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoMapper, SpuInfo> implements ISpuInfoService {

    @Resource(name = "asyncTaskThreadPool")
    private Executor executor;

    @Resource
    private ICategoryService categoryService;

    @Resource
    private ISpuImageService spuImageService;

    @Resource
    private ISpuDescService spuDescService;

    @Resource
    private ISpuBaseAttrService spuBaseAttrService;

    @Resource
    private ISpuSaleAttrService spuSaleAttrService;

    @Resource
    private ISkuAttrService skuAttrService;

    @Resource
    private ISkuInfoService skuInfoService;

    @Resource
    private IGroupService groupService;

    @Resource
    private IMsgService msgService;

    /**
     * 新增
     */
    @Transactional
    @Override
    public void saveEntity(SpuUpdateRequest request) {
        if(null == request.getSkuInfos() || request.getSkuInfos().size() == 0){
            throw new XmallException(ResultCode.PRODUCT_SAVE_INFO_ERROR);
        }

        SpuInfo entity = new SpuInfo();
        BeanUtils.copyProperties(request.getInfo(), entity);
        entity.setStatus(UpStatusEnum.DOWN.getStatus());
        entity.setImage(spuImageService.getDefaultImage(request.getImages()));
        entity.setEsVersion(CommonConstants.INIT_ES_VERSION);
        this.save(entity);

        spuImageService.save(entity.getId(), request.getImages());

        spuDescService.save(entity.getId(), request.getDescs());

        spuBaseAttrService.save(entity.getId(), request.getBaseAttrs());

        Map<Long, Long> attrIdMap = spuSaleAttrService.save(entity.getId(), request.getSaleAttrs());

        skuInfoService.save(entity.getId(), attrIdMap, request.getSkuInfos());

        msgService.sendProductUpdateMsg(entity.getId(), CommonConstants.INIT_ES_VERSION);
    }

    /**
     * 编辑
     */
    @Transactional
    @Override
    public void updateEntity(SpuUpdateRequest request) {
        Long spuId = request.getId();
        SpuInfo spuInfo = this.getById(request.getId());
        XmallUtils.notNull(spuInfo);

        SpuInfo updateSpuInfo = new SpuInfo();
        updateSpuInfo.setId(request.getId());
        updateSpuInfo.setName(request.getInfo().getName());
        updateSpuInfo.setTitle(request.getInfo().getTitle());
        updateSpuInfo.setImage(spuImageService.getDefaultImage(request.getImages()));
        updateSpuInfo.setEsVersion(spuInfo.getEsVersion() + 1);
        this.updateById(updateSpuInfo);

        spuImageService.update(spuId, request.getImages());

        spuDescService.update(spuId, request.getDescs());

        spuBaseAttrService.update(spuId, request.getBaseAttrs());

        Map<Long, Long> attrIdMap = spuSaleAttrService.update(spuId, request.getSaleAttrs());

        skuInfoService.update(spuId, attrIdMap, request.getSkuInfos());

        msgService.sendProductUpdateMsg(spuId, updateSpuInfo.getEsVersion());
    }

    /**
     * 删除
     */
    @Transactional
    @Override
    public void deleteEntity(Long id) {
        SpuInfo spuInfo = this.getById(id);
        XmallUtils.notNull(spuInfo);

        this.removeById(id);

        spuImageService.delete(id);

        spuDescService.delete(id);

        spuBaseAttrService.delete(id);

        spuSaleAttrService.delete(id);

        skuInfoService.delete(id);

        msgService.sendProductDeleteMsg(id);
    }

    /**
     * 构造es对象
     */
    @Override
    public List<EsSkuDto> buildEsSku(Long spuId, Integer esVersion) {
        QueryWrapper<SpuInfo> wrapper = new QueryWrapper<SpuInfo>().eq("id", spuId);
        wrapper.eq(null != esVersion, "es_version", esVersion);

        SpuInfo spuInfo = this.getOne(wrapper);
        if(null == spuInfo) {
            return new ArrayList<>();
        }

        // sku列表
        List<SkuInfo> skuList = skuInfoService.list(new QueryWrapper<SkuInfo>().eq("spu_id", spuId));
        List<EsSkuDto> esSkuList = ConvertUtils.SpuModule.INSTANCE.toEsList(skuList);

        // 规格参数
        List<SpuBaseAttrDto> spuBaseAttrList = spuBaseAttrService.searchableList(spuId);

        esSkuList.forEach(esSku -> {
            esSku.setCategoryId(spuInfo.getCategoryId());
            esSku.setEsVersion(spuInfo.getEsVersion());
            esSku.setSpuAttrList(ConvertUtils.SpuBaseAttrModule.INSTANCE.toEsList(spuBaseAttrList));
            esSku.setHasStock(esSku.getStockNum() - esSku.getLockedNum() > 0);
        });

        return esSkuList;
    }

    /**
     * 分页列表
     */
    @Override
    public Page<SpuInfoDto> listPage(SpuListPageQueryRequest request) {
        Page<SpuInfoDto> result = new Page<>();

        QueryWrapper query = new QueryWrapper();
        if(null != request.getCategoryId()) {
            query.in("category_id", categoryService.childIdList(request.getCategoryId()));
        }
        query.like(StringUtils.isNotBlank(request.getName()), "name", request.getName());

        Page<SpuInfo> page = this.page(new Page(request.getPage(), request.getPageSize()), query);

        BeanUtils.copyProperties(page, result);
        result.setRecords(ConvertUtils.SpuModule.INSTANCE.toDtoList(page.getRecords()));
        return result;
    }


    /**
     * 详情
     */
    @Override
    public SpuResponseDto apiInfo(Long id) throws Exception{
        SpuResponseDto result = new SpuResponseDto();
        SpuInfo spuInfo = this.getById(id);
        XmallUtils.notNull(spuInfo);

        // 基本信息
        result.setInfo(ConvertUtils.SpuModule.INSTANCE.toDto(spuInfo));

        // 图片信息
        CompletableFuture<Void> spuImageFuture = CompletableFuture.runAsync(() -> result.setImages(spuImageService.list(id)), executor);

        // 描述信息
        CompletableFuture<Void> spuDescFuture = CompletableFuture.runAsync(() -> result.setDescs(spuDescService.list(id)), executor);

        // 规格参数
        CompletableFuture<Void> spuGroupAttrFuture = CompletableFuture.runAsync(() -> {
            List<Long> categoryIds = categoryService.hierarchyIdList(spuInfo.getCategoryId());
            List<GroupDto> groupList = groupService.listWithCascade(new GroupQueryParams().setCategoryIds(categoryIds));
            groupList = spuBaseAttrService.fillValueAndRemoveEmpty(id, groupList);
            result.setGroupAttrs(groupList);
        }, executor);

        // sku列表
        CompletableFuture<List<SkuInfoDto>> preSkuFuture = CompletableFuture.supplyAsync(() -> {
            List<SkuInfoDto> skuInfoDtoList = skuInfoService.listWithCascade(new SkuQueryParams().setSpuId(id));
            result.setSkuInfos(skuInfoDtoList);
            result.setHasSaleAttrs(skuInfoDtoList.stream().anyMatch(skuInfoDto -> skuInfoDto.getSkuAttrList().size() > 0));
            return skuInfoDtoList;
        }, executor);

        // sku属性列表
        CompletableFuture<Void> skuAttrFuture = preSkuFuture.thenAcceptAsync(skuInfoDtoList -> {
            // 获取销售属性排序信息
            List<SpuSaleAttrDto> wholeSaleAttrs = spuSaleAttrService.listWithCascade(id);
            Map<Long, Integer> wholeAttrSortList = wholeSaleAttrs.stream().collect(Collectors.toMap(SpuSaleAttrDto::getId, SpuSaleAttrDto::getSort));
            // 根据sku列表提取sku属性列表（接口使用）
            List<SpuSaleAttrDto> saleAttrs = skuAttrService.extractSkuAttrList(wholeAttrSortList, skuInfoDtoList);
            result.setSaleAttrs(saleAttrs);
        }, executor);

        CompletableFuture<Void> allFuture = CompletableFuture.allOf(spuImageFuture, spuDescFuture, spuGroupAttrFuture, preSkuFuture, skuAttrFuture);
        allFuture.get();
        return result;
    }

    /**
     * 详情
     */
    @Override
    public SpuResponseDto info(Long id) throws Exception {
        SpuResponseDto result = new SpuResponseDto();
        SpuInfo spuInfo = this.getById(id);
        XmallUtils.notNull(spuInfo);

        // 基本信息
        SpuInfoDto spuInfoDto = ConvertUtils.SpuModule.INSTANCE.toDto(spuInfo);
        result.setInfo(spuInfoDto);

        // 分类名称
        CompletableFuture<Void> spuInfoFuture = CompletableFuture.runAsync(() -> categoryService.setSpuInfo(spuInfoDto), executor);

        // 图片信息
        CompletableFuture<Void> spuImageFuture = CompletableFuture.runAsync(() -> {
            result.setImages(spuImageService.list(id));
            result.setDefaultSpuImageSn(spuImageService.getDefaultImageSn(result.getImages()));
        }, executor);

        // 描述信息
        CompletableFuture<Void> spuDescFuture = CompletableFuture.runAsync(() -> {
            result.setDescs(spuDescService.list(id));
        }, executor);

        // 规格参数
        CompletableFuture<Void> spuGroupAttrFuture = CompletableFuture.runAsync(() -> {
            List<Long> categoryIds = categoryService.hierarchyIdList(spuInfo.getCategoryId());
            List<GroupDto> groupAttrs = groupService.listWithCascade(new GroupQueryParams().setCategoryIds(categoryIds));
            spuBaseAttrService.fillValue(id, groupAttrs);
            result.setGroupAttrs(groupAttrs);
        }, executor);

        // 销售参数
        CompletableFuture<Void> spuSaleAttrFuture = CompletableFuture.runAsync(() -> {
            List<SpuSaleAttrDto> saleAttrs = spuSaleAttrService.listWithCascade(id);
            skuAttrService.fillValue(id, saleAttrs);
            result.setSaleAttrs(saleAttrs);
        }, executor);

        // sku 列表
        CompletableFuture<Void> skuInfoFuture = CompletableFuture.runAsync(() -> {
            List<SkuInfoDto> skuInfoDtoList = skuInfoService.listWithCascade(new SkuQueryParams().setSpuId(id));
            skuInfoService.assemblySpuAndSkuImage(id, skuInfoDtoList);
            result.setSkuInfos(skuInfoDtoList);
            result.setHasSaleAttrs(skuInfoDtoList.stream().anyMatch(skuInfoDto -> skuInfoDto.getSkuAttrList().size() > 0));
        }, executor);

        CompletableFuture<Void> allFuture = CompletableFuture.allOf(
                spuInfoFuture, spuImageFuture, spuDescFuture,
                spuGroupAttrFuture, spuSaleAttrFuture, skuInfoFuture);
        allFuture.get();
        return result;
    }

}
